/*
 * UBus.h
 */

#ifndef NETUBUS_UBUS_H_
#define NETUBUS_UBUS_H_

#include <atomic>
#include <list>
#include <memory>
#include <string>
#include <thread>
#include "json.hpp"

extern "C" {
#include "libubox/blobmsg.h"
#include "libubox/blobmsg_json.h"
#include "libubus.h"
}

using json = nlohmann::json;

struct UbusObject
{
    uint32_t id;
    uint32_t type_id;
    std::string path;
    json signature;
};

struct UBusCallback
{
    std::function<void(json)> callback;
};

class UBusCallbackStaticManager
{
   private:
    static std::map<int, std::shared_ptr<UBusCallback>> &GetEventsMap()
    {
        static std::map<int, std::shared_ptr<UBusCallback>> events;
        return events;
    }

   public:
    UBusCallbackStaticManager();
    virtual ~UBusCallbackStaticManager() = default;

    static void addCallbackHandler(int id, std::shared_ptr<UBusCallback> handler)
    {
        if (GetEventsMap().count(id) != 0)
        {
            return;
        }

        GetEventsMap()[id] = handler;
    }

    static std::shared_ptr<UBusCallback> getCallbackHandler(int id)
    {
        if (GetEventsMap().count(id) == 1)
        {
            return GetEventsMap()[id];
        }
        return nullptr;
    }
};

class UBus
{
   private:
    struct UBusConnection
    {
        int timeout;
        struct blob_buf buf;
        struct ubus_context *ctx;
        struct uloop_timeout uloopTimeout;
    };

    std::thread uloopThread;
    bool threadRunning;
    std::unique_ptr<UBusConnection> m_connectionptr;

   protected:
    void StartUloopThread();
    void StopUloopThread();

   public:
    std::function<void(std::unique_ptr<UbusObject>)> signatureCallback;
    std::function<void(json)> callCallback;

    UBus();
    virtual ~UBus();

    void Connect();
    void Disconnect();
    void Objects();
    void Subscribe(std::string path, std::function<void(json)> callback);
    void unSubscribe(std::string path, std::function<void(json)> callback);
};

class notify
{
   private:
    struct UBusConnection
    {
        int timeout;
        struct blob_buf buf;
        struct ubus_context *ctx;
        struct uloop_timeout uloopTimeout;
    };
    std::unique_ptr<UBusConnection> m_connectionptr;

    std::thread uloopThread;
    bool threadRunning;

    struct ubus_object *obj;

   protected:
    void StartUloopThread();
    void StopUloopThread();

   public:
    notify();
    virtual ~notify();

    void Connect();
    void Disconnect();
    void Objects();
    void notifier(std::string path, std::string msg);
};

#endif /* NETUBUS_UBUS_H_ */
